// 更新视图
function updateView() {
  console.log('视图更新')
}

// 属性修改时进行监听
function defineReactive(target, key, value) {
  // 深度监听
  observe(value)

  // 核心API
  Object.defineProperty(target, key, {
    get() {
      return value
    },
    set(newVal) {
      if (value !== newVal) {
        // 新值如果是对象时，直接像对象内属性赋值，需要在此处监听
        observe(newVal)

        value = newVal
        updateView()
      }
    },
  })
}

// 从新定义数组原型
const oldArrayProperty = Array.prototype
// Object.create创建一个没有任何属性的新对象；这里将原型指向oldArrayProperty，扩展方法时不会影响Array原型
const arrProto = Object.create(oldArrayProperty)
// 定义需要扩展的属性
const property = ['push', 'pop', 'shift', 'unshift', 'splice']
property.forEach((method) => {
  arrProto[method] = function () {
    updateView()
    oldArrayProperty[method].call(this, ...arguments)
  }
})

console.log(arrProto)

// 监听属性
function observe(target) {
  if (typeof target !== 'object' || target === null) {
    return target
  }

  if (Array.isArray(target)) {
    // 如果是数组就将原型替换成扩展后的原型，此时调用的数据方法则会促发页面更新
    target.__proto__ = arrProto
  }

  for (let key in target) {
    defineReactive(target, key, target[key])
  }
}

// 定义对象
const data = {
  id: 1,
  name: '张三',
  class: '班级',
  info: {
    age: 12,
  },
  arr: [],
}

observe(data)

data.name = '李四'
data.info.age = 20
data.class = { num: 2 }
data.class.num = 22

// 无法监听
data.add = 'add' // Vue.set
delete data.id // Vue.delete

// 监听数组
data.arr.push(1)

// 1. 深度监听时，需要一次性全部递归结束，计算量大
// 2. 无法监听新增/删除属性，需要调用 Vue.set / Vue.delete 函数
// 3. 对于数组需要进行原型方法的扩展
